Fox's Git Mirrors
docs/self-hosting.md HEAD (ed7be254) Text, 7.91 KB
Self-Hosting Omegon Armory
Armory is designed to be self-hosted as two separable surfaces:
T282828
1. Static catalog site/API
2. OCI artifact registry
Operators can run either surface independently, but a full mirror runs both.
Modes
Static-Only Catalog
Use this when you want a browsable internal catalog and generated API, but artifacts can still point to GHCR or another upstream registry.
Build:
T282828
cd site
npm install
npm run build
Serve T383838site/dist/ with Caddy, Nginx, Cloudflare Pages, GitHub Pages, Netlify, S3/R2 static hosting, or any static web server.
This mode provides:
• human package catalog
• T383838/api/index.json
• install commands
• provenance and source links
It does not mirror OCI blobs unless the site data was generated against a self-hosted registry and artifacts were published there.
Full Mirror
Use this when you want your own catalog plus your own OCI artifact storage.
T282828
Static site/API -> https://armory.example.com
OCI registry -> registry.example.com/omegon-armory/*
Armory index artifact -> registry.example.com/omegon-armory/index:latest
Build artifacts for the destination namespace:
T282828
python3 scripts/build-oci-artifacts.py \\
--registry registry.example.com/omegon-armory \\
--out dist/oci
Generate site/API data from that artifact index:
T282828
python3 scripts/generate-site-data.py \\
--oci dist/oci \\
--out site/src/data/armory.json \\
--api site/public/api/index.json
Build the static site:
T282828
cd site && npm run build
Publish artifacts:
T282828
oras login registry.example.com
python3 scripts/publish-oci-artifacts.py --out dist/oci --sign
Private/Federated Armory
Organizations often need:
T282828
official Styrene packages
+ private profiles
+ private skills/personas/tones
+ private catalog agents
+ private extensions
The preferred first implementation is a single merged index published at the private registry:
T282828
registry.example.com/omegon-armory/index:latest
A private profile can then reference both official and private dependencies through the merged index:
T282828
profile/acme-secure-dev
-> official skill/security
-> official skill/typescript
-> private skill/acme-compliance
-> private persona/acme-engineer
-> private extension/acme-jira
Multi-index federation can come later. Start with one merged index because it keeps profile dependency resolution deterministic and easy to explain.
Local Full Mirror with Compose
A local self-host stack should provide:
T282828
http://localhost:8080 # static Armory catalog
http://localhost:8080/api/index.json
http://localhost:5000/v2/ # OCI registry API
localhost:5000/omegon-armory/* # OCI artifacts
Recommended files:
T282828
deploy/selfhost/
├── compose.yml
├── zot-config.json
├── Caddyfile
├── README.md
└── .env.example
Minimal compose shape:
T282828
services:
registry:
image: ghcr.io/project-zot/zot-linux-amd64:v2.1.4
command: ["serve", "/etc/zot/config.json"]
ports:
- "5000:5000"
volumes:
- ./zot-config.json:/etc/zot/config.json:ro
- registry-data:/var/lib/registry
site:
image: caddy:2
ports:
- "8080:80"
volumes:
- ../../site/dist:/usr/share/caddy:ro
- ./Caddyfile:/etc/caddy/Caddyfile:ro
volumes:
registry-data:
Minimal zot config:
T282828
{
"distSpecVersion": "1.1.0",
"storage": {
"rootDirectory": "/var/lib/registry"
},
"http": {
"address": "0.0.0.0",
"port": "5000"
},
"log": {
"level": "info"
}
}
Minimal Caddyfile:
T282828
:80 {
root * /usr/share/caddy
file_server
}
Production zot + Cloudflare R2
The Kubernetes deployment in T383838deploy/zot-r2/ runs zot with Cloudflare R2 as S3-compatible object storage.
Architecture:
T282828
OCI client
-> registry.example.com
-> zot Deployment
-> Cloudflare R2 bucket
Use this when you want:
• cheap blob storage
• public anonymous pulls
• authenticated pushes
• Cloudflare edge controls/rate limiting
• Kubernetes deployment ownership
Deploy:
T282828
cp deploy/zot-r2/secret.example.yaml deploy/zot-r2/secret.yaml
# fill AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY
# edit deploy/zot-r2/configmap.yaml for R2 endpoint and bucket
# optionally configure ingress
kubectl apply -k deploy/zot-r2
Verify:
T282828
kubectl -n omegon-armory rollout status deploy/omegon-armory-zot
kubectl -n omegon-armory port-forward svc/omegon-armory-zot 5000:5000
curl -s http://localhost:5000/v2/
Registry Path Layout
Mirrors should preserve upstream path layout:
T282828
registry.example.com/omegon-armory/index:latest
registry.example.com/omegon-armory/skills/security:1.0.0
registry.example.com/omegon-armory/personas/tutor:1.0.0
registry.example.com/omegon-armory/tones/concise:1.0.0
registry.example.com/omegon-armory/catalog/styrene.coding-agent:1.0.0
registry.example.com/omegon-armory/profiles/alpharius:1.0.0
Preserving paths lets the index be rewritten by namespace rather than by package semantics.
Mirror Workflow
A future mirror command should:
1. Pull upstream T383838index:latest.
2. Pull every artifact listed in the index.
3. Push artifacts to the destination namespace.
4. Rewrite T383838ref fields in the destination index.
5. Push destination T383838index:latest.
6. Copy or regenerate signatures and attestations according to local trust policy.
Expected command shape:
T282828
python3 scripts/mirror-oci-artifacts.py \\
--from ghcr.io/styrene-lab/omegon-armory \\
--to registry.example.com/omegon-armory
Trust Policy
Self-hosted Armory must make trust explicit.
Official public installs should verify Styrene signatures. Private installs should use the operator's trust policy. Local development may allow unsigned artifacts only with an explicit flag.
Example policy:
T282828
[trust]
allow_unsigned = false
[[trust.identities]]
issuer = "https://token.actions.githubusercontent.com"
subject = "repo:styrene-lab/omegon-armory:*"
[[trust.keys]]
name = "acme"
public_key = "cosign.pub"
Recommended behavior:
• public official registry: require official signature
• private registry: verify configured keyless identity or public key
• local development: require T383838--allow-unsigned for unsigned artifacts
Authentication
Local development can run without auth.
Production should use:
• anonymous pull + authenticated push for public mirrors
• authenticated pull/push for private mirrors
• ingress auth, token service, mTLS, or network restriction depending on environment
Typical commands:
T282828
oras login registry.example.com
cosign login registry.example.com
If Omegon adds native registry auth, it should mirror this UX:
T282828
omegon registry login registry.example.com
Backup and Restore
Static site:
• rebuild from source
• redeploy T383838site/dist/
OCI registry:
• back up registry blob storage volume or bucket
• back up signing keys if key-based signing is used
• preserve source repo and generated release metadata
For zot + R2, the R2 bucket is the artifact store and the repo can regenerate the index and site.
Implementation Tasks
1. Add T383838deploy/selfhost/ compose stack for local zot + Caddy.
2. Add T383838scripts/selfhost-build.py to wrap artifact build, site data generation, site build, and optional publish.
3. Add T383838scripts/mirror-oci-artifacts.py to mirror upstream artifacts into a destination namespace.
4. Add environment/config support for T383838ARMORY_REGISTRY and T383838ARMORY_SITE_URL.
5. Add justfile or Makefile targets:
• T383838selfhost-build
• T383838selfhost-up
• T383838selfhost-down
• T383838selfhost-publish
• T383838selfhost-mirror
6. Add docs for static-only, full mirror, R2/zot, auth, trust, backup, and private overlays.
7. Extend the Armory index/site model to include profiles and profile dependencies.
Served by rngit 1.5.2 - Generated in 0.03s